package com.boarsoft.boar.config.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.boarsoft.bean.ReplyInfo;
import com.boarsoft.boar.app.AppBiz;
import com.boarsoft.boar.app.AppInstBiz;
import com.boarsoft.boar.config.entity.ConfigVar;
import com.boarsoft.boar.config.entity.ConfigVarApp;
import com.boarsoft.boar.config.entity.ConfigVarEnv;
import com.boarsoft.boar.config.var.ConfigVarAppBiz;
import com.boarsoft.boar.config.var.ConfigVarBiz;
import com.boarsoft.boar.config.var.ConfigVarEnvBiz;
import com.boarsoft.boar.context.ActionContext;
import com.boarsoft.boar.entity.AppInfo;
import com.boarsoft.boar.entity.AppInst;
import com.boarsoft.common.Util;
import com.boarsoft.common.util.FileUtil;
import com.boarsoft.config.core.ConfigVarSync;
import com.boarsoft.hibernate.dao.SimpleDao;
import com.boarsoft.rpc.core.RpcContext;
import org.hibernate.exception.ConstraintViolationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Component("configVarSvc")
public class ConfigVarServiceImpl implements ConfigVarService{
    private static final Logger log = LoggerFactory.getLogger(ConfigVarServiceImpl.class);
    @Autowired
    protected ConfigVarBiz configVarBiz;

    @Autowired
    protected ConfigVarAppBiz configVarAppBiz;

    @Autowired
    protected AppInstBiz appInstBiz;

    //@Autowired
    protected ConfigVarSync configVarSync;

    @Autowired
    protected AppBiz appBiz;

    @Autowired
    protected ConfigVarEnvBiz configVarEnvBiz;
    /**
     *
     * @param appId 应用id
     * @param group 组
     * @param name 名字
     * @param value	取值
     * @return 是否成功
     */
    @Override public Boolean save(String appId, String group, String name, String value) {
        return save(null,appId, group, name, null, value);
    }

    /**
     * 保存配置监息
     * @param appId 应用id
     * @param group 组
     * @param name 名字
     * @param ver 版本号
     * @param value 取值
     * @return 是否成功
     */
    @Override public Boolean save(String id, String appId, String group, String name, String ver, String value){
        String projId = configVarAppBiz.getProjIdByAppId(appId);
        ConfigVar configVar = new ConfigVar();
        configVar.setProjId(projId);
        configVar.setGroup(group);
        configVar.setName(name);
        configVar.setValue(value);
        configVar.setStatus(ConfigVar.STATUS_INUSE);
        configVar.setVer(ver);
        List<ConfigVar> configVars= configVarBiz.findByStatus(projId,name, ConfigVar.STATUS_INUSE);
        if(Util.strIsEmpty(ver)){
            if((configVars != null && configVars.size() > 0)) {
                ver = configVars.get(0).getVer();
                configVar.setVer(ver);
            } else {
                ver = "1.0.0";
                configVar.setVer(ver);
            }
        }
        String varId = id;
        if(Util.strIsEmpty(id)){
            ConfigVar a = configVarBiz.findByName(projId,name,ver);
            if (null != a) {
                varId = a.getId();
                configVar.setId(a.getId());
                configVarBiz.upd(configVar);
            } else {
                configVarBiz.add(configVar);
                varId = configVar.getId();
            }
        } else {
            configVar.setId(id);
            configVarBiz.upd(configVar);
        }
        ConfigVarApp configVarApp = new ConfigVarApp();
        configVarApp.setVarId(varId);
        configVarApp.setAppId(appId);
        try {
            configVarAppBiz.save(configVarApp);
        }catch (DataIntegrityViolationException e){
            return this.put(configVar);
        }
        return this.put(configVar);
    }

    @Override
    public ReplyInfo<Object> list(String appId,String ipAddr,String env) {
        List<ConfigVar> configVars = configVarBiz.list2(appId,env);
        AppInfo appInfo = appBiz.get(appId);
        if (null != appInfo) {
            AppInst appInst = new AppInst();
            appInst.setAppId(appId);
            appInst.setStatus(AppInst.STATUS_RUNNING);
            appInst.setDeployPath(appInfo.getDeployPath());
            appInst.setIp(ipAddr);
            appInst.setPort(appInfo.getPort());
            appInst.setServerId("00000000000000000000000000000000");
            appInst.setUser(appInfo.getUser());
            appInst.setTempPath(appInfo.getTempPath());
            try {
                appInstBiz.add(appInst);
            } catch (DataIntegrityViolationException | ConstraintViolationException e){
                //违反约束
                //appInstBiz.update(appInst);
            }
        }
        for (int i = 0; i < configVars.size(); i++) {
            ConfigVar configVar = configVars.get(i);
            configVar.setApps(null);
        }
        return new ReplyInfo<Object>(true, configVars);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void clone(String appId, String fromEnv, String toEnv) {
        if("init".equals(fromEnv)){
            List<ConfigVar> configVars=configVarBiz.listAll();
            for(ConfigVar cv:configVars) {
                ConfigVarEnv fromConfigEnv = new ConfigVarEnv();
                fromConfigEnv.setVarId(cv.getId());
                fromConfigEnv.setEnv(toEnv);
                fromConfigEnv.setValue(cv.getValue());
                configVarEnvBiz.add(fromConfigEnv);
            }
        }else {
            List<ConfigVarEnv> configVars=configVarEnvBiz.findByEnv(appId, fromEnv);
            for(ConfigVarEnv fromConfigVarEnv : configVars){
                ConfigVarEnv toConfigEnv = new ConfigVarEnv();
                toConfigEnv.setEnv(toEnv);
                toConfigEnv.setValue(fromConfigVarEnv.getValue());
                toConfigEnv.setVarId(fromConfigVarEnv.getVarId());
                configVarEnvBiz.add(toConfigEnv);
            }
        }
    }

    @Override
    public void exportConfig(String appId,String fromEnv,String exportRoot) throws FileNotFoundException {
        List<ConfigVarEnv> configVarEnvs = configVarEnvBiz.findByEnv(appId,fromEnv);
        String exportPath=exportRoot+"/configvar/";
        if(!new File(exportPath).exists()){
            new File(exportPath).mkdirs();
        }
        FileUtil.write(new File(exportPath+"config_var_env.data"), JSON.toJSONString(configVarEnvs));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void importConfig(String zipFile) throws IOException {
        String context = FileUtil.read(new File(zipFile));
        List<ConfigVarEnv> lst= JSONObject.parseArray(context,ConfigVarEnv.class);
        for(ConfigVarEnv cve:lst){
            configVarEnvBiz.add(cve);
        }
    }
    /**
     * 推送配置监息
     * @return 是否成功
     */
    public Boolean put(ConfigVar o) {
        // 查询当前变量关联的应用
        List<AppInfo> appLt = configVarAppBiz.list(o.getId());
        log.info("Sync config var {}/{} to {} application", //
                o.getGroup(), o.getName(), appLt.size());
        Map<String, String> pm = new HashMap<String, String>();
        pm.put(o.getName(), o.getValue());
        //
        Map<String, String> rm = new HashMap<String, String>();
        for (AppInfo a : appLt) {
            List<AppInst> instLt = appInstBiz.list(//
                    null, a.getId(), null, AppInst.STATUS_RUNNING);
            for (AppInst i : instLt) {
                log.info("Sync config var {}/{} to {}", //
                        o.getGroup(), o.getName(), i.getAddr());
                RpcContext.specify2(i.getAddr());
                try {
                    configVarSync.put(o.getGroup(), pm);
                    rm.put(i.getAddr(), "success");
                } catch (Exception e) {
                    log.error("Error on sync config var {}/{} to {}", //
                            o.getGroup(), o.getName(), i.getAddr(), e);
                    rm.put(i.getAddr(), e.getMessage());
                } finally {
                    RpcContext.specify2(null);
                }
            }
        }
        return true;
    }

}